package fem2;

import java.util.ArrayList;
import java.util.Set;

import junit.framework.Assert;

import org.junit.Test;

import fem2.element.StructuralElement;
import fem2.enu.State;
import fem2.level_set.Crack;
import fem2.material.StVenantKirchhoffMM;
import fem2.pre_and_post.PatchMeshGenerator;

public class LevelSetTest {

	public Model createModel() {
		MeshGenerator mg = new PatchMeshGenerator(6, 6, 0, 0, 1, 1);
		Mesh mesh = mg.getMesh(2);
		Model m = new Model(mesh);

		double E = 2;
		double nu = 0.3;

		MaterialModel mm = new StVenantKirchhoffMM(E, nu, 1.0, 0.0, State.PLANE_STRESS);
		for (int i = 0; i < mesh.countFaces(); i++) {
			m.addElement(new StructuralElement(mesh.getFace(i), mm));
		}

		return m;
	}

	@Test
	public void testLevel() {
		Model m = createModel();
		Mesh mesh = m.getMesh();

		double[] tip_start = new double[] { 0, 2.5 };
		double[] tip_delta = new double[] { 1.5, 0.0 };
		Crack c = new Crack(m, tip_start, tip_delta);

		for (int i = 0; i < mesh.countNodes(); i++) {
			double v = c.getLevelSet("psi").valueAt(mesh.getNode(i));
			double[] p = mesh.getNode(i).getPosition();
			Debugger.watch(p[0], p[1], v);
		}
		System.out.println("--------------------------------");
		for (int i = 0; i < mesh.countNodes(); i++) {
			double v = c.getLevelSet("phi").valueAt(mesh.getNode(i));
			double[] p = mesh.getNode(i).getPosition();
			Debugger.watch(p[0], p[1], v);
		}
		System.out.println("--------------------------------");
		Set<Element> psiSet = c.getLevelSet("psi").getZeroLevelElements();
		for (Element e : psiSet) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		Set<Element> phiSet = c.getLevelSet("phi").getZeroLevelElements();
		for (Element e : phiSet) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		double[] tip1 = c.getCrackTip();
		Debugger.watch(tip1);
		Assert.assertEquals(tip_start[0] + tip_delta[0], tip1[0]);
		Assert.assertEquals(tip_start[1] + tip_delta[1], tip1[1]);
		System.out.println("--------------------------------");
		for (Element e : c.getSplitElements()) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		for (Element e : c.getCrackTipElements()) {
			Debugger.watch(e.getId());
		}
	}

	@Test
	public void testPropagation() {
		Model m = createModel();
		Mesh mesh = m.getMesh();

		double[] tip_start = new double[] { 0, 2.5 };
		double[] tip_delta = new double[] { 1.5, 0.0 };
		Crack c = new Crack(m, tip_start, tip_delta);
		double r = 1.0;
		double theta = Math.PI / 9;
		c.propagate(r, theta);

		for (int i = 0; i < mesh.countNodes(); i++) {
			double v = c.getLevelSet("psi").valueAt(mesh.getNode(i));
			double[] p = mesh.getNode(i).getPosition();
			Debugger.watch(p[0], p[1], v);
		}
		System.out.println("--------------------------------");
		for (int i = 0; i < mesh.countNodes(); i++) {
			double v = c.getLevelSet("phi").valueAt(mesh.getNode(i));
			double[] p = mesh.getNode(i).getPosition();
			Debugger.watch(p[0], p[1], v);
		}
		System.out.println("--------------------------------");
		Set<Element> psiSet = c.getLevelSet("psi").getZeroLevelElements();
		for (Element e : psiSet) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		Set<Element> phiSet = c.getLevelSet("phi").getZeroLevelElements();
		for (Element e : phiSet) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		double[] tip1 = c.getCrackTip();
		Debugger.watch(tip1);
		Assert.assertEquals(tip_start[0] + tip_delta[0] + r * Math.cos(theta), tip1[0], 1e-6);
		Assert.assertEquals(tip_start[1] + tip_delta[1] + r * Math.sin(theta), tip1[1], 1e-6);
		System.out.println("--------------------------------");
		for (Element e : c.getSplitElements()) {
			Debugger.watch(e.getId());
		}
		System.out.println("--------------------------------");
		for (Element e : c.getCrackTipElements()) {
			Debugger.watch(e.getId());
		}
	}

	@Test
	public void testIntersection() {
		Model m = createModel();

		double[] tip_start = new double[] { 0, 2.5 };
		double[] tip_delta = new double[] { 1.5, 0.0 };
		Crack c = new Crack(m, tip_start, tip_delta);

		Set<Element> splitElements = c.getSplitElements();
		for (Element e : splitElements) {
			ArrayList<double[]> points = c.computeIntersectionAt(e);
			for (double[] xi : points) {
				Debugger.watch(xi);
				Debugger.watch(e.getMeshPart().XAt(xi));
			}
		}
	}
}
